import random
from datetime import datetime

from flask import current_app, jsonify
from flask import json
from flask import make_response
from flask import session

from info import constants, db
from info import redis_store
from info.libs.yuntongxun.sms import CCP
from info.models import User
from info.utils.captcha.captcha import captcha
from info.utils.response_code import RET
from . import passport_blue
from flask import request
import re

"""
接口注意点
１目的：接口写好之后是给前端工程师使用的
２请求的url地址
３请求方式
４请求的参数
５返回值
获取图片验证码
    １获取参数　校验参数
    ２生成图片验证码
    ３保存图片验证码到redis
    4判断是否有上一个图片验证码编号　如果有则删除上次
    ５返回图片验证码

获取短信验证码思路分析
    １获取请求参数
    ２校验参数，为空验证
    ３校验手机号的格式
    ４通过图片验证码编号　取出redis中的图片验证码Ａ
    5判断图片验证码Ａ是否过期
    ６删除图片验证码Ａ
    ７判断请求参数中的验证码Ｂ和redis中的验证码Ａ是否相同
    ８生成短信验证码（随机数）
    ９调用ccp模块发送短信
    １０判断短信是否发送成功
    １１保存短信验证码到redis
    12返回响应

注册用户思路分析
    １获取请求参数（手机号，短信验证码，密码）
    ２校验参数为空校验
    ３通过手机号作为key取出redis中的短信验证码
    ４判断短信验证码是否过期
    ５删除redsi中的短信验证码
    ６判断redis中的短信验证码和传入进来的短信验证码是否相等
    ７创建用户对象，设置属性
    ８保存用户到数据库
    ９返回响应

登陆用户思路分析
    １获取请求参数
    ２校验参数　为空校验
    3根据用户手机取出，用户对象
    ４判断用户对象是否存在
    ５校验密码是否正确
    ６记录用户登陆信息到session
    ７返回响应
"""""
# 功能描述：退出登陆
#     请求路径:/passport/logout
#     请求方式:POST
#     请求参数:无
#     返回值:errno,errmsg
@passport_blue.route('/logout', methods=['POST'])
def logout():
#     清除session
    session.pop("user_id",None)
    session.pop("nick_name",None)
    session.pop("mobile",None)
# 返回响应
    return jsonify(errno=RET.OK,errmsg="退出成功")

# 功能描述:登陆用户
#     请求路径:/passport/login
#     请求方式:POST
#     请求参数:mobile,password
#     返回值:error,errmsg
@passport_blue.route('/login', methods=['POST'])
def login():
    # １获取请求参数
    mobile = request.json.get("mobile")
    password = request.json.get("password")
    # ２校验参数　为空校验
    if not all([mobile,password]):
        return jsonify(errno=RET.PARAMERR,errmsg="参数不全")
    # 3根据用户手机取出，用户对象
    try:
        user = User.query.filter(User.mobile == mobile).first()
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR,errmsg="获取用户失败")
    # ４判断用户对象是否存在
    if not user:
        return jsonify(errno=RET.NODATA,errmsg="该用户不存在")
    # ５校验密码是否正确
    # if user.password_hash != password:
    # 和密文进行比对　使用check_password_hash(密文，明文)　返回的是True和Flase
    if not user.check_password(password):
        return jsonify(errno=RET.DATAERR,errmsg="密码错误")
    # ６记录用户登陆信息到session
    session["user_id"]=user.id
    session["nick_name"]=user.nick_name
    session["mobile"]=user.mobile

    # 记录用户最后一次登陆时间
    user.last_login = datetime.now()
    # 如果每次修改模型类的对象之后，都需要进行commit操作这个过程很麻烦
    # 可以设置数据库的另一个配置信息SQLALCHEM_COMMIT_ON_TEARDOWN

    # try:
    #     db.session.commit()
    # except Exception as e:
    #     current_app.logger.error(e)

    # ７返回响应
    return jsonify(errno=RET.OK,errmsg="登陆成功")

# 功能描述　：注册用户
#     请求路径:/passport/register
#     请求方式:POST
#     请求参数：mobile,sms_code,password
#     返回值:erno,errmsg
@passport_blue.route('/register', methods=['POST'])
def register():
    # １获取请求参数（手机号，短信验证码，密码）
    # json_data = request.data
    # dict_data = json.loads(json_data)
    # 上面两句话合成一句话
    dict_data = request.get_json()  # 等价于request.json
    mobile = dict_data.get("mobile")
    sms_code = dict_data.get("sms_code")
    password = dict_data.get("password")
    # ２校验参数为空校验
    if not all([mobile, sms_code, password]):
        return jsonify(error=RET.PARAMERR, errmsg="参数不全")
    # ３通过手机号作为key取出redis中的短信验证码
    try:
        redis_sms_code = redis_store.get("sms_code:%s" % mobile)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="短信验证码获取失败")
    # ４判断短信验证码是否过期
    if not redis_sms_code:
        return jsonify(error=RET.NODATA, errmsg="短信验证码已过期")
    # ５删除redsi中的短信验证码
    try:
        redis_store.delete("sms_code%s" % mobile)
    except Exception as e:
        return jsonify(errno=RET.NODATA, errmsg="短信验证吗删除异常")
    # ６判断redis中的短信验证码和传入进来的短信验证码是否相等
    if redis_sms_code != sms_code:
        return jsonify(errno=RET.DATAERR, errmsg="短信验证码填写错误")
    # ７创建用户对象，设置属性
    user = User()
    user.nick_name = mobile
    # user.password_hash = password  # 未加密
    # 使用的是werkzueg.security提供的一对方法　generator_password_hash()加密方法
    user.password = password  # 加密
    user.mobile = mobile
    user.signature = "这个人那很懒，什么都没有"
    # ８保存用户到数据库
    try:
        db.session.add(user)
        db.session.commit()
    except Exception as e:
        current_app.logger.error(e)
        db.session.rollback()
        return jsonify(errno=RET.DBERR, errmsg="注册用户失败")
    # ９返回响应
    return jsonify(errno=RET.OK, errmsg="注册成功")


# 功能描述　获取短信验证码
# 请求路径:/passport/sms_code
# 请求方式:POST
# 请求参数:mobile,image_code,image_code_id
# 返回值:error,errmsg
@passport_blue.route('/sms_code', methods=['POST'])
def sms_code():
    # １获取请求参数
    json_data = request.data
    dict_data = json.loads(json_data)
    mobile = dict_data.get("mobile")
    image_code = dict_data.get("image_code")
    image_code_id = dict_data.get("image_code_id")
    # ２校验参数，为空验证
    if not all([mobile, image_code, image_code_id]):
        return jsonify(errno=RET.PARAMERR, errmsg="参数不完整")

    # ３校验手机号的格式
    if not re.match("1[356789]\\d{9}", mobile):
        return jsonify(errno=RET.DATAERR, errmsg="手机号格式不正确")
    # ４通过图片验证码编号　取出redis中的图片验证码Ａ
    try:
        redis_image_code = redis_store.get("image_code:%s" % image_code_id)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="图片验证码获取失败")
    # 5判断图片验证码Ａ是否过期
    if not redis_image_code:
        return jsonify(errno=RET.NODATA, errmsg="图片验证码过期")
    # ６删除图片验证码Ａ
    try:
        redis_store.delete("image_code:%s" % image_code_id)
    except Exception as  e:
        current_app.logger.error(e)
        return jsonify(errno=RET.NODATA, errmsg="删除图片验证码失败")
    # ７判断请求参数中的验证码Ｂ和redis中的验证码Ａ是否相同
    if image_code.lower() != redis_image_code.lower():
        return jsonify(errno=RET.DATAERR, errmsg="图片验证码填写错误")
    # ８生成短信验证码（随机数）
    sms_code = "%06d" % random.randint(0, 999999)
    print(sms_code)
    # ９调用ccp模块发送短信
    # try:
    #     ccp = CCP()
    #     result = ccp.send_template_sms(mobile, [sms_code, constants.SMS_CODE_REDIS_EXPIRES / 60], 1)
    # except Exception as e:
    #     current_app.logger.error(e)
    #     return jsonify(errno=RET.THIRDERR, errmsg="云通讯异常")
    # # １０判断短信是否发送成功
    # if result == -1:
    #     return jsonify(errno=RET.DATAERR, errmsg="短信发送失败")

    # １１保存短信验证码到redis
    try:
        redis_store.set("sms_code:%s" % mobile, sms_code, constants.SMS_CODE_REDIS_EXPIRES)
    except Exception as e:
        current_app.logger.error(e)
        return jsonify(errno=RET.DBERR, errmsg="短信验证保存失败")
    # 12返回响应
    return jsonify(errno=RET.OK, errmsg="发送成功")


# /功能描述：获取图片验证码
# 请求路径:/passport/image_code
# 请求方式：GET
# 请求参数:cur_id,pre_id
# 返回值　:图片验证码

@passport_blue.route('/image_code', methods=['GET'])
def image_code():
    #     １获取参数　校验参数
    cur_id = request.args.get("cur_id")
    pre_id = request.args.get("pre_id")

    if not cur_id:
        return "图片验证码编号不全"
    # ２生成图片验证码
    name, text, imagae_data = captcha.generate_captcha()
    # ３保存图片验证码到redis   key,vaalue mac_age(图片验证码有效期)
    try:
        redis_store.set("image_code:%s" % cur_id, text, constants.IMAGE_CODE_REDIS_EXPIRES)
        # ４判断是否有上一个图片验证码编号　如果有则删除上次
        if pre_id:
            redis_store.delete("image_code%s" % pre_id)
    except Exception as e:
        current_app.logger.error(e)
        return "图片验证码保存失败"

    # ５返回图片验证码
    response = make_response(imagae_data)
    response.headers["Content-Type"] = "image/png"
    return response
